﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Itenso.TimePeriod;
using LogManager.Base;
using LogManager.Base.Data;
using LogManager.Excel;
using LogManager.Helpers;
using LogManager.ViewModels;
using LogManager.ViewModels.Filter;
using MvcContrib.Pagination;
using MvcContrib.Sorting;
using MvcContrib.UI.Grid;
using System.Web.Routing;

namespace LogManager.Controllers
{
    public class EventController : BaseController
    {
        private readonly IEventService _eventService;
        private readonly IEventTypeService _typeService;

        /// <summary>
        /// Create new event controller
        /// </summary>
        /// <param name="eventService">Event service</param>
        public EventController(IEventService eventService, IEventTypeService typeService)
        {
            _eventService = eventService;
            _typeService = typeService;
        }

        /// <summary>
        /// Get a list of events filtered by the given parameters
        /// </summary>
        /// <param name="filter">Filter parameters</param>
        /// <param name="datePage">Date paging number</param>
        /// <param name="sortOptions">Sort options for the events</param>
        /// <param name="page">Pagenumber</param>
        /// <param name="count">Number of items per page</param>
        /// <returns></returns>
        [HttpGet]
        public ActionResult List(EventParameterFilter filter, GridSortOptions sortOptions, int datePage = 1, int page = 1, int count = 20, string view="List")
        {
            if (sortOptions.Column == null)
            {
                sortOptions.Column = "TimeStamp";
                sortOptions.Direction = SortDirection.Descending;
            }

            var events = _eventService
                .GetEvents(new TimeRange(DatePager.FromDate(datePage), DatePager.ToDate(datePage)), filter.ServerName,filter.LogName)
                .Filter(level:filter.Level,user:filter.User,type:filter.Type)
                .Search(filter.Property, filter.SearchValue)
                .OrderBy(sortOptions.Column, sortOptions.Direction)
                .AsPagination(page, count);

            var routeValues = new RouteValueDictionary(filter);
            routeValues["fileName"] = "Events_" + DateTime.Now.ToShortDateString().Replace('.', '_') + ".xls";

            var model = new EventList
                {
                    Events = events,
                    SortOptions = sortOptions,
                    DownloadUrl = Url.Action("ListDownload", routeValues),
                    View = view
                };
            
            return PartialView(model);
        }        

        /// <summary>
        /// Returns the detail properties of a log
        /// </summary>
        /// <param name="serverName">Name of the server</param>
        /// <param name="logName">Name of the log</param>
        /// <param name="id">Row id of the event</param>
        /// <param name="sortOptions">Sort options for the events</param>
        /// <param name="page">Pagenumber</param>
        /// <param name="count">Number of items per page</param>
        /// <returns>View that shows the detailed event</returns>
        [HttpGet]
        public ActionResult Detail(string serverName, string logName,string id,GridSortOptions sortOptions,int page=1, int count=20)
        {
            IEvent model = _eventService.GetEvent(serverName, logName, id);
            return View(model);
        }

        /// <summary>
        /// Create excel file download for all events filtered by parameters
        /// </summary>
        /// <param name="fileName">Name of the download file</param>
        /// <param name="filter">EventParameterFilter to filter events</param>
        /// <param name="sortOptions">Sort options for the events</param>
        /// <param name="datePage">Date paging number</param>
        /// <returns>Excel file</returns>
        public ExcelResult<IEvent> ListDownload(string fileName,EventParameterFilter filter, GridSortOptions sortOptions, int datePage = 1, string view = "List")
        {
            //Based on the view create url
            //Load all events (no server get limit)
            var events = _eventService
                .GetEvents(GetTimePeriod(filter.Start,filter.End,datePage), filter.ServerName,
                           filter.LogName)
                .Filter(level: filter.Level, user: filter.User, type: filter.Type)
                .Search(filter.Property, filter.SearchValue)
                .OrderBy(sortOptions.Column, sortOptions.Direction)
                .All();

            var properties = _typeService.All().SelectMany(t => t.CommonProperties).Distinct();


            //Create excel result
            var excel = new ExcelResult<IEvent>(events) { Title = fileName }
                .Columns(column =>
                {
                    column.For(e => e.ServerName);
                    column.For(e => e.LogName);
                    column.For(e => e.Type);
                    column.For(e => e.Level);
                    column.For(e => e.Message);
                    column.For(e => e.User);
                    column.For(e => e.TimeStamp);

                    column.For(e => e.Properties.GetValueOrDefault("ExceptionType", null)).Named("ExceptionType");
                    column.For(e => e.Properties.GetValueOrDefault("ExceptionDetail", null)).Named("ExceptionDetail ");
                    column.For(e => e.Properties.GetValueOrDefault("StackTraceFileName", null)).Named("StackTraceFileName ");
                    column.For(e => e.Properties.GetValueOrDefault("StackTraceFileLineNumber", null)).Named("StackTraceFileLineNumber");
                    column.For(e => e.Properties.GetValueOrDefault("RequestUrl", null)).Named("RequestUrl");
                    column.For(e => e.Properties.GetValueOrDefault("RequestPath", null)).Named("RequestPath ");
                    column.For(e => e.Properties.GetValueOrDefault("UserHostAddress", null)).Named("UserHostAddress");
                    column.For(e => e.Properties.GetValueOrDefault("IdentityName", null)).Named("IdentityName");

                    //note: does not work
                    //foreach (var propertyName in properties)
                    //{
                    //    column.Custom(e => e.Properties.GetValueOrDefault(propertyName, null)).Named(propertyName);
                    //}
                });

            return excel;
        }    

        /// <summary>
        /// Get time period by deciding between date page or defined range method. Prefore defined range.
        /// </summary>
        /// <param name="start">Start date</param>
        /// <param name="end">End date</param>
        /// <param name="datePage">Date page</param>
        /// <returns></returns>
        private ITimePeriod GetTimePeriod(string start, string end,int datePage)
        {
            DateTime startDate, endDate;
            if (DateTime.TryParse(start, out startDate) && DateTime.TryParse(end, out endDate))
                return new TimeRange(startDate,endDate);
            return new TimeRange(DatePager.FromDate(datePage), DatePager.ToDate(datePage));
        }
    }
}